package com.test.springboot.service;

import com.test.springboot.bean.Employee;
import com.test.springboot.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

/**
 * @create: 2019-06-25 19:20
 **/
//在这里没有指定CacheManager,是因为我们只定义了一个Manager,而不是多个，所以不用指定是哪一个
@CacheConfig(cacheNames = "emp") //抽取缓存的公共配置，在类上定义该类中所有缓存组件的名称，这样就不用在每次使用时声名了。
@Service
public class EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    /**
     * 将方法运行结果进行缓存，以后再要相同的数据，直接从缓存中获取，不在调用方法；
     * <p>
     * 几个属性：
     * CacheManager管理多个Cache组件的，对缓存的真正CRUD操作在Cache组件中，每个缓存组件有自己的唯一名字
     * cacheNames/value：指定缓存组件的名字；
     * key:缓存数据使用的key；可以用他来指定。默认使用方法参数的值，如参数为1时key=1；
     * 编写时可使用SpEL表达式，key="#id"；参数id的值。#a0,#p0,#root.args[0]；
     * keyGenerator：key的生成器，可以自己指定key的生成器的组件id,与key只能二选一，不能同时选择两个；
     * cacheResolver:缓存解析器，同样与缓存管理器只能二选一；
     * condition: 指定符合条件的情况下才缓存；condition = "#id > 0":参数大于0时才进行缓存;
     * unless: 否定缓存；当unless指定的条件为true，方法的返回值就不会被缓存；可以获取到结果进行判断，unless = "#result == null",
     * #result即表示结果；
     * sync: 是否使用异步模式；
     * <p>
     * 原理：
     * 1.自动配置类：CacheAutoConfiguration
     * 2.
     *
     * @param id
     * @return
     */
    @Cacheable(/*cacheNames = {"emp"}, keyGenerator = "myKeyGenerator"*/)
    public Employee getEmpById(Integer id) {
        System.out.println("查询了" + id + "号员工");
        return employeeMapper.getEmpById(id);
    }


    /**
     * @param employee
     * @return
     * @CachePut: 既调用方法，又更新缓存数据;
     * 修改了数据库的某个数据，同时又更新缓存;
     * 运行时机：
     * 先调用目标方法，然后将目标方法的结果缓存起来；
     * 测试步骤：
     * 1.查询1号员工，将查询到的结果缓存起来。以后再查询时候使用缓存中的数据。
     * (第一次查询时，使用的key是默认的方法参数，即key=1。)
     * 2.更新1号的数据。
     * (该次更新后重新缓存时，如果不指定key则会使用默认的key，即key=employee对象)
     * 3.在更新时定义key，与查询时缓存的key一致
     * (key = "#employee.id"与key = "#result.id"效果是一样的，只是使用返回结果中的参数更好一点)
     */
    @CachePut(/*value = "emp", key = "#employee.id"*/ key = "#result.id")
    public Employee updateEmp(Employee employee) {
        System.out.println("更新了" + employee.getId() + "号员工");
        employeeMapper.updateEmp(employee);
        return employee;
    }

    /**
     * @param id
     * @CacheEvict: 清除缓存
     * key: 指定要清除的key;
     * allEntries: 是否清除所有，true清除所有；
     * beforeInvocation: 缓存清除是否在方法执行之前，默认为false,表示在方法之后执行；
     */
    @CacheEvict(/*value = "emp", key = "#id",*/ allEntries = true)
    public void deleteEmp(Integer id) {
        System.out.println("删除了缓存中的" + id + "号员工");

        //如果清除是在方法之后，这里出现异常了则清除不会执行
        //int i = 10/0;
    }

    /**
     * @param lastName
     * @return
     * @Caching: 定义复杂的缓存规则
     */
    @Caching(
            cacheable = {
                    @Cacheable(/*value = "emp",*/ key = "#lastName")
            },
            put = {
                    @CachePut(/*value = "emp",*/ key = "#result.id"),
                    @CachePut(/*value = "emp",*/ key = "#result.email")
            }
    )
    public Employee getEmlByLastName(String lastName) {
        return employeeMapper.getEmpByLastName(lastName);
    }
}
